package com.googlecode.pdfbricks.splitter;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.googlecode.pdfbricks.engine.PDFOperator;
import com.googlecode.pdfbricks.engine.base.Executable;
import com.googlecode.pdfbricks.engine.base.Validatable;
import com.googlecode.pdfbricks.engine.exception.CommandExecuteException;
import com.googlecode.pdfbricks.engine.exception.CommandValidateException;
import com.googlecode.pdfbricks.engine.exception.PDFOperationException;
import com.googlecode.pdfbricks.engine.to.FilePageRange;
import com.googlecode.pdfbricks.engine.to.PageRange;
import com.googlecode.pdfbricks.engine.util.FileUtils;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.PdfCopy;
import com.lowagie.text.pdf.PdfReader;

public class SplitCommand implements Executable,Validatable {

	private static final Log log = LogFactory.getLog(SplitCommand.class);
	
	private File fromFile;
	
	private List toFilePageRangeList;
	
	public void execute(){
		validate();
		execute0();
	}
	
	private void execute0(){
		Document document = null;
		PdfReader reader = null;
		PdfCopy copy = null;
		
		int i=0,j;
		FilePageRange fpr=null;
		int toFPRListSize=toFilePageRangeList.size();		
		List prList=null;
		PageRange pr=null;
		int prlSize=0;
		
		PDFOperator pdfOpt = new PDFOperator();
		try {
			reader = new PdfReader(fromFile.getPath());
			for (;i<toFPRListSize;i++) {
				fpr=(FilePageRange) toFilePageRangeList.get(i);
				FileUtils.createFile(fpr.getFilePath());
				document = new Document();
				copy = new PdfCopy(document, new BufferedOutputStream(
						new FileOutputStream(fpr.getFilePath())));
				document.open();
				
				prList = fpr.getPageRangeList();
				prlSize=prList.size();
				if (fpr.isAllPages()) {
					// Reader reads all the page and copy to PdfCopy.
					pdfOpt.extractAll(copy, reader);
				} else {
					for (j=0;j<prlSize;j++) {
						pr=(PageRange) prList.get(j);
						pdfOpt.extract(copy, reader, pr.getStartIndex(), pr
								.getEndIndex());
					}
				}
				document.close();
			}
		} catch (IOException ex) {
			throw new CommandExecuteException(ex.getMessage(), ex);
		} catch (DocumentException ex) {
			throw new CommandExecuteException(ex.getMessage(), ex);
		}  catch (PDFOperationException ex) {
			throw new CommandExecuteException(ex.getMessage(), ex);
		} finally {
			if (reader != null) {
				reader.close();
			}if(document!=null){
				document.close();
			}
		}
	}

	public void run() {
		execute();		
	}

	public void validate() {
		if(fromFile==null){
			throw new CommandValidateException("No file path is indicated which pdfbricks should split from!");
		}
		if(toFilePageRangeList==null||toFilePageRangeList.isEmpty()){
			throw new CommandValidateException("No file path is indicated which pdfbricks should split to!");
		}
		int size=toFilePageRangeList.size();
		FilePageRange fpr=null;
		File file=null;
		for(int i=0;i<size;i++){
			fpr=(FilePageRange)toFilePageRangeList.get(i);
			
			if(fpr.getFilePath()==null){
				throw new CommandValidateException("File path is not indicated!");
			}
			
			file=new File(fpr.getFilePath());
			if(file.exists()){
				throw new CommandValidateException(fpr.getFilePath()+" already exist!");
			}
		}		
	}
	
	public File getFromFile() {
		return fromFile;
	}

	public void setFromFile(File fromFile) {
		this.fromFile = fromFile;
	}

	public SplitCommand addToFilePageRange(FilePageRange filePageRange){
		if(toFilePageRangeList==null){
			toFilePageRangeList=new ArrayList();
		}
		toFilePageRangeList.add(filePageRange);
		return this;
	}
	
	public List getToFilePageRangeList() {
		return toFilePageRangeList;
	}

	public void setToFilePageRangeList(List toFilePageRangeList) {
		this.toFilePageRangeList = toFilePageRangeList;
	}

}
